use std::fs;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::io::{BufRead, BufReader, Write};
use unicode_width::UnicodeWidthStr;
use importer::{
    movie::{
        Movie, SearchMovie, disc_list, disc_delete, disc_edit
    },
    input::{change_txt_to_json}
};
use importer::movie::disc_add;
use movie::error::{Error, Result};
use crate::{
    models::{User},
    users::get_users
};

#[derive(Debug, Clone)]
pub struct Interface{
    path: Option<PathBuf>, // 用Option类型允许延迟初始化
}

#[derive(Debug)]
pub struct ModifyMovie {
    pub new_disc: Option<u32>,
    pub new_year: Option<String>,
    pub new_title: Option<String>,
    pub new_remark: Option<Option<String>>, // 双层Option：外层None=不修改，内层None=清空备注
}

impl Interface {
    pub fn new() -> Self {
        Self { path: None }
    }

    /// cargo run -- login -u root
    /// 再输入密码
    pub fn handle_login(&self, username: String) -> Result<()> {
        if let Some(user) = get_users().iter().find(|u| u.username.eq_ignore_ascii_case(username.as_str())) {
            println!("请输入密码");
            match rpassword::read_password() {
                Ok(password) => {
                    if user.password.eq_ignore_ascii_case(password.as_str()) {
                        println!("登录成功 密码: {:?}", password);
                        self.log_success(user)
                    } else {
                        Err(Error::Internal("密码错误, 登录失败".to_string()))
                    }
                }
                Err(_) => Err(Error::Internal("未输入密码, 登录失败".to_string())),
            }
        } else {
            Err(Error::Internal("用户没找到".to_string()))
        }
    }

    fn log_success(&self, user: &User) -> Result<()> {
        Ok(fs::write(".session", user.to_string())?)
    }

    /// 登出  cargo run -- logout
    pub fn handle_logout(&self) -> Result<()> {
        let result = OpenOptions::new().read(true).open(PathBuf::from(".path"))?;
        let reader = BufReader::new(result);
        for path in reader.lines().map(|line| line.unwrap().trim().to_string()).filter(|line| !line.is_empty()) {
            println!("{}", path);
            let _ = fs::remove_file(path);
        }
        let _ = fs::remove_file(".path");
        Ok(())
    }

    /// cargo run -- change -P /root/rust_workspace/movie/DVDs.txt
    pub fn handle_change(&mut self, path: String) -> Result<()> {
        println!("文件路径 {:?}", path.clone());
        if !Path::new(".session").exists() {
            return Err(Error::Internal(format!("文件 {} 不存在", ".session")));
        }
        let buf = PathBuf::from(&path);
        self.path = Some(buf.clone());
        let mut dest = buf.parent().unwrap().to_path_buf();
        if dest.is_dir() {
            dest.push(".session");
        }
        let mut json = buf.parent().unwrap().to_path_buf();
        // 如果目标是目录，则在目录下保留.session文件名
        if json.is_dir() {
            json.push("DVDs.json");
        }
        // let exists = fs::exists(&dest).map_err(|e| Error::Internal(format!("检查登录状态失败: {}", e)))?;
        // if !exists {
        let _ = change_txt_to_json(buf.clone())?;
        let source = PathBuf::from(".session");
        // 把 .session 文件移动到和 DVDs.json 同一目录下
        let _ = fs::rename(&source, &dest);
        // }
        // append(true) 和 truncate(...) 不能同时使用
        let mut file = OpenOptions::new().create(true).write(true).truncate(!Path::new(".path").exists()).open(".path").expect("无法打开或创建 .path 文件");
        writeln!(file, "{}", json.to_str().expect("路径包含非 UTF-8 字符").to_string()).expect("写入 .path 文件失败");
        writeln!(file, "{}", dest.to_str().expect("路径包含非 UTF-8 字符").to_string()).expect("写入 .path 文件失败");
        Ok(())
    }


    pub fn handle_select(&self, search: SearchMovie) -> Result<()> {
        println!("{:?}", search);
        let path_buf = PathBuf::from(".path");
        if !path_buf.exists() {
            return Err(Error::Internal("错误：.path 文件不存在，请先使用 change 命令设置数据文件路径".into()));
        }
        let result = OpenOptions::new().read(true).open(path_buf)?;
        let reader = BufReader::new(result);
        let lines: Vec<String> = reader.lines().filter_map(|line| line.ok()).collect();
        let file_path = lines.get(0).cloned().unwrap();
        let path = Path::new(file_path.as_str());
        println!("{:?}", path);
        if !path.exists() {
            eprintln!("警告：.path 中记录的文件 {} 不存在，可能导致操作失败", file_path);
        }
        let movies = disc_list(path, search)?;
        let _ = self.list_movie(movies);
        Ok(())
    }

    pub fn list_movie(&self, movies: Vec<Movie>) -> Result<()> {
        println!("{:<5}{:<7}{:<100}{:<40}{:<5}", "disc", "year", "title", "remark", "no");
        println!("{:-<155}", "");
        movies.iter().for_each(|movie| {
            let remark = movie.remark.as_deref().unwrap_or("");
            let title = self.pad_dispaly_width(&movie.title, 100);
            let remark = self.pad_dispaly_width(&remark.to_string(), 40);
            println!("{:<5}{:<7}{}{}{}", movie.disc, movie.year, title, remark, movie.no);
        });
        Ok(())
    }

    fn pad_dispaly_width(&self, s: &str, target_width: usize) -> String {
        let width = UnicodeWidthStr::width(s);
        format!("{}{}", s, " ".repeat(target_width.saturating_sub(width)))
    }

    /// 修改功能核心逻辑
    pub fn handle_update(&mut self, search: SearchMovie, modify: ModifyMovie) -> Result<usize> {
        println!("{:?}", search);
        let path_buf = PathBuf::from(".path");
        if !path_buf.exists() {
            return Err(Error::Internal("错误：.path 文件不存在，请先使用 change 命令设置数据文件路径".into()));
        }
        let result = OpenOptions::new().read(true).open(path_buf)?;
        let reader = BufReader::new(result);
        let lines: Vec<String> = reader.lines().filter_map(|line| line.ok()).collect();
        let file_path = lines.get(0).cloned().unwrap();
        let path = Path::new(file_path.as_str());
        println!("{:?}", path);
        if !path.exists() {
            eprintln!("警告：.path 中记录的文件 {} 不存在，可能导致操作失败", file_path);
        }
        let modified = disc_edit(path, search, |movie| {
            // 如果提供了new_disc，则修改disc
            if let Some(new_disc) = modify.new_disc {
                movie.disc = new_disc;
            }
            // 如果提供了new_year，则修改year
            if let Some(new_year) = &modify.new_year {
                movie.year = new_year.clone();
            }
            // 如果提供了new_title，则修改title
            if let Some(new_title) = &modify.new_title {
                movie.title = new_title.clone();
            }
            // 如果提供了new_remark，则修改remark（可能设为Some或None）
            if let Some(new_remark) = &modify.new_remark {
                movie.remark = new_remark.clone();
            }
        })?;
        println!("修改了 {} 条记录", modified.clone());
        Ok(modified)
    }

    /// 删除功能核心逻辑
    pub fn handle_delete(&mut self, search: SearchMovie) -> Result<usize> {
        println!("{:?}", search);
        let path_buf = PathBuf::from(".path");
        if !path_buf.exists() {
            return Err(Error::Internal("错误：.path 文件不存在，请先使用 change 命令设置数据文件路径".into()));
        }
        let result = OpenOptions::new().read(true).open(path_buf)?;
        let reader = BufReader::new(result);
        let lines: Vec<String> = reader.lines().filter_map(|line| line.ok()).collect();
        let file_path = lines.get(0).cloned().unwrap();
        let path = Path::new(file_path.as_str());
        println!("{:?}", path);
        if !path.exists() {
            eprintln!("警告：.path 中记录的文件 {} 不存在，可能导致操作失败", file_path);
        }
        let deleted = disc_delete(path, search)?;
        println!("删除了 {} 条记录", deleted.clone());
        Ok(deleted)
    }

    pub fn handle_add(&self, movies: Vec<Movie>) -> Result<usize> {
        println!("{:?}", movies);
        let path_buf = PathBuf::from(".path");
        if !path_buf.exists() {
            return Err(Error::Internal("错误：.path 文件不存在，请先使用 change 命令设置数据文件路径".into()));
        }
        let result = OpenOptions::new().read(true).open(path_buf)?;
        let reader = BufReader::new(result);
        let lines: Vec<String> = reader.lines().filter_map(|line| line.ok()).collect();
        let file_path = lines.get(0).cloned().unwrap();
        let path = Path::new(file_path.as_str());
        println!("{:?}", path);
        if !path.exists() {
            eprintln!("警告：.path 中记录的文件 {} 不存在，可能导致操作失败", file_path);
        }
        let added_count = disc_add(path, movies)?;
        println!("添加了 {} 条记录", added_count);
        Ok(added_count)
    }
}
